/*
** Config.c
** handle configuration variables.
*/

#include "dis6502.h"

#define CONFIG_MAGIC10        "DIS6502PRF10"
#define CONFIG_MAGIC          "DIS6502PRF13"

static char szConfigPath[_MAX_PATH];

/*
** Read configuration from a file
*/
static BOOL ConfigRead(HWND hDlg, char *szPath, CONFIG *Cfg)
{
int fd;
char szMagic[20];

     if ((fd = open(szPath, _O_RDONLY | _O_BINARY)) < 0)
          {
          if (hDlg)
               Error(hDlg, IDS_ERR_OPENING_FILE, "Error while opening file %s", szPath);
          }
     else {
          memset(szMagic, 0, sizeof(szMagic));
          read(fd, szMagic, strlen(CONFIG_MAGIC));
          if (! memcmp(szMagic, CONFIG_MAGIC10, strlen(CONFIG_MAGIC10)))
               {

               /*
               ** this is a profile file version 1.0. Read the configuration.
               */
               memset(Cfg, 0, sizeof(CONFIG));
               read(fd, &Cfg->config10, sizeof(CONFIG10));
               close(fd);
               return TRUE;
               }
          else if (! memcmp(szMagic, CONFIG_MAGIC, strlen(CONFIG_MAGIC)))
               {
     
               /*
               ** this is a profile file version 1.3. Read the configuration.
               */
               memset(Cfg, 0, sizeof(CONFIG));
               read(fd, Cfg, sizeof(CONFIG));
               close(fd);
               return TRUE;
               }
          else {
               if (hDlg)
                    Error(hDlg, IDS_ERR_BAD_CONFIG, "File %s is not a valid profile !", szConfigPath);
               close(fd);
               }
          }
     return FALSE;
}

/*
** set default configuration with MAC/65 settings.
*/
void ConfigInit(void)
{
char *pSlash;

     /*
     ** initialize the profile default path
     */
     GetModuleFileName(hInst, szConfigPath, sizeof(szConfigPath) - 20);
     if (pSlash = strrchr(szConfigPath, '\\'))
          strcpy(pSlash + 1, szComputerName);
     else strcat(szConfigPath, szComputerName);
     strcat(szConfigPath, ".PRF");

     /*
     ** Assembler dependent configuration
     ** ---------------------------------
     ** general
     */
     strcpy(Config.config10.szComment, ";");
     strcpy(Config.config10.szHex, "$");
     Config.config10.bIllegalOpcodes = FALSE;
     Config.config10.bLineNumbering = FALSE;
     Config.config10.bAlignInstructions = TRUE;
     Config.config10.bUseHex = TRUE;
     Config.config10.bShowAforImplicite = TRUE;

     /*
     ** directive syntax
     */
     strcpy(Config.config10.szBYTE, ".BYTE");
     strcpy(Config.config10.szWORD, ".WORD");
     strcpy(Config.config10.szSBYTE, ".SBYTE");
     strcpy(Config.config10.szORG, "*=");
     strcpy(Config.config10.szEQU, "=");
     strcpy(Config.config10.szENDHead, ".END");
     strcpy(Config.config10.szENDTail, "");
     strcpy(Config.config10.szLOWHead, " <");
     strcpy(Config.config10.szLOWTail, "");
     strcpy(Config.config10.szHIGHHead, " >");
     strcpy(Config.config10.szHIGHTail, "");
     strcpy(Config.config10.szByteSeparator, ",");
     Config.config10.bNumOnlyInByte = FALSE;
     Config.config10.bWordAllowed = TRUE;
     Config.config10.bSByteAllowed = TRUE;
     Config.config10.bEndNeedFilename = FALSE;

     /*
     ** Include files
     */
     strcpy(Config.config10.szINCLUDEHead, ".INCLUDE #");
     strcpy(Config.config10.szINCLUDETail, "");
     Config.config10.wNbLinesPerInclude = 500;
     Config.config10.bOneMainFile = TRUE;
     Config.config10.bIncludeAllowed = TRUE;

     /*
     ** Addition to assembler syntax
     */
     strcpy(Config.szDS, ".DS");
     Config.bDSAllowed = TRUE;

     /*
     ** Assembler independent configuration
     ** -----------------------------------
     ** format
     */
     wConfigNbWordsPerLine = 2;
     wConfigNbBytesPerLine = 4;
     wConfigNbCharPerString = 12;

     /*
     ** other configuration parameters
     */
     bConfigDumpInternal = FALSE;
     bConfigNoDisassembly = FALSE;

     /*
     ** now read default profile if it exists
     */
     ConfigRead(0, szConfigPath, &Config);
}

/*
** Output format dialog proc.
*/
BOOL __export CALLBACK OutputFormatProc(HWND hDlg, UINT message, WORD wParam, LONG lParam)
{
BOOL bTrans;

     switch (message)
          {
          case WM_INITDIALOG:
               SendDlgItemMessage(hDlg, IDC_WORDPERLINE, EM_LIMITTEXT, 2, 0);
               SendDlgItemMessage(hDlg, IDC_BYTEPERLINE, EM_LIMITTEXT, 2, 0);
               SendDlgItemMessage(hDlg, IDC_CHARPERLINE, EM_LIMITTEXT, 2, 0);
               SetDlgItemInt(hDlg, IDC_WORDPERLINE, wConfigNbWordsPerLine, FALSE);
               SetDlgItemInt(hDlg, IDC_BYTEPERLINE, wConfigNbBytesPerLine, FALSE);
               SetDlgItemInt(hDlg, IDC_CHARPERLINE, wConfigNbCharPerString, FALSE);
               return TRUE;

          case WM_COMMAND:
               switch (wParam)
                    {
                    case IDOK:
                         wConfigNbWordsPerLine = GetDlgItemInt(hDlg, IDC_WORDPERLINE, &bTrans, FALSE);
                         wConfigNbBytesPerLine = GetDlgItemInt(hDlg, IDC_BYTEPERLINE, &bTrans, FALSE);
                         wConfigNbCharPerString = GetDlgItemInt(hDlg, IDC_CHARPERLINE, &bTrans, FALSE);
                         if (wDumpSegment != NO_DUMP)
                              DumpDisassemble(hDlg);
                         EndDialog(hDlg, TRUE);
                         return TRUE;

                    case IDCANCEL:
                         EndDialog(hDlg, FALSE);
                         return TRUE;
                    }
               break;

          case WM_CTLCOLOR:

               /*
               ** change background color to gray.
               */
               if (HIWORD(lParam) == CTLCOLOR_STATIC || HIWORD(lParam) == CTLCOLOR_BTN || HIWORD(lParam) == CTLCOLOR_DLG)
                    {
                    SetBkColor((HDC) wParam, RGB(192, 192, 192));
                    return (BOOL) GetStockObject(LTGRAY_BRUSH);
                    }
               return FALSE;
          }
     return FALSE;
}

/*
** fill all dialog box fields with Config structure.
*/
static void ConfigSetDialog(HWND hDlg, CONFIG *Cfg)
{
     /*
     ** limit edit size.
     */
     SendDlgItemMessage(hDlg, IDC_COMMENT, EM_LIMITTEXT, MAX_CONFIG_STRING_LNG - 1, 0);
     SendDlgItemMessage(hDlg, IDC_HEXNOTATION, EM_LIMITTEXT, MAX_CONFIG_STRING_LNG - 1, 0);
     SendDlgItemMessage(hDlg, IDC_BYTESYNTAX, EM_LIMITTEXT, MAX_CONFIG_STRING_LNG - 1, 0);
     SendDlgItemMessage(hDlg, IDC_WORDSYNTAX, EM_LIMITTEXT, MAX_CONFIG_STRING_LNG - 1, 0);
     SendDlgItemMessage(hDlg, IDC_SBYTESYNTAX, EM_LIMITTEXT, MAX_CONFIG_STRING_LNG - 1, 0);
     SendDlgItemMessage(hDlg, IDC_ORGSYNTAX, EM_LIMITTEXT, MAX_CONFIG_STRING_LNG - 1, 0);
     SendDlgItemMessage(hDlg, IDC_EQUSYNTAX, EM_LIMITTEXT, MAX_CONFIG_STRING_LNG - 1, 0);
     SendDlgItemMessage(hDlg, IDC_ENDSYNTAX, EM_LIMITTEXT, MAX_CONFIG_STRING_LNG - 1, 0);
     SendDlgItemMessage(hDlg, IDC_ENDTAIL, EM_LIMITTEXT, MAX_CONFIG_STRING_LNG - 1, 0);
     SendDlgItemMessage(hDlg, IDC_LOWHEADSYNTAX, EM_LIMITTEXT, MAX_CONFIG_STRING_LNG - 1, 0);
     SendDlgItemMessage(hDlg, IDC_LOWTAILSYNTAX, EM_LIMITTEXT, MAX_CONFIG_STRING_LNG - 1, 0);
     SendDlgItemMessage(hDlg, IDC_HIGHHEADSYNTAX, EM_LIMITTEXT, MAX_CONFIG_STRING_LNG - 1, 0);
     SendDlgItemMessage(hDlg, IDC_HIGHTAILSYNTAX, EM_LIMITTEXT, MAX_CONFIG_STRING_LNG - 1, 0);
     SendDlgItemMessage(hDlg, IDC_BYTESEPARATOR, EM_LIMITTEXT, MAX_CONFIG_STRING_LNG - 1, 0);
     SendDlgItemMessage(hDlg, IDC_INCLUDEHEAD, EM_LIMITTEXT, MAX_CONFIG_STRING_LNG - 1, 0);
     SendDlgItemMessage(hDlg, IDC_INCLUDETAIL, EM_LIMITTEXT, MAX_CONFIG_STRING_LNG - 1, 0);
     SendDlgItemMessage(hDlg, IDC_DSSYNTAX, EM_LIMITTEXT, MAX_CONFIG_STRING_LNG - 1, 0);

     /*
     ** set dialog fields.
     */
     SetDlgItemText(hDlg, IDC_COMMENT, Cfg->config10.szComment);
     SetDlgItemText(hDlg, IDC_HEXNOTATION, Cfg->config10.szHex);
     CheckDlgButton(hDlg, IDC_ILLEGALINSTRUCTION, Cfg->config10.bIllegalOpcodes);
     CheckDlgButton(hDlg, IDC_LINENUMBERING, Cfg->config10.bLineNumbering);
     CheckDlgButton(hDlg, IDC_ALIGNINSTRUCTION, Cfg->config10.bAlignInstructions);
     CheckDlgButton(hDlg, IDC_USEHEX, Cfg->config10.bUseHex);
     SetDlgItemText(hDlg, IDC_BYTESYNTAX, Cfg->config10.szBYTE);
     SetDlgItemText(hDlg, IDC_WORDSYNTAX, Cfg->config10.szWORD);
     SetDlgItemText(hDlg, IDC_SBYTESYNTAX, Cfg->config10.szSBYTE);
     SetDlgItemText(hDlg, IDC_ORGSYNTAX, Cfg->config10.szORG);
     SetDlgItemText(hDlg, IDC_EQUSYNTAX, Cfg->config10.szEQU);
     SetDlgItemText(hDlg, IDC_ENDSYNTAX, Cfg->config10.szENDHead);
     SetDlgItemText(hDlg, IDC_ENDTAIL, Cfg->config10.szENDTail);
     SetDlgItemText(hDlg, IDC_LOWHEADSYNTAX, Cfg->config10.szLOWHead);
     SetDlgItemText(hDlg, IDC_LOWTAILSYNTAX, Cfg->config10.szLOWTail);
     SetDlgItemText(hDlg, IDC_HIGHHEADSYNTAX, Cfg->config10.szHIGHHead);
     SetDlgItemText(hDlg, IDC_HIGHTAILSYNTAX, Cfg->config10.szHIGHTail);
     SetDlgItemText(hDlg, IDC_BYTESEPARATOR, Cfg->config10.szByteSeparator);
     CheckDlgButton(hDlg, IDC_NUMONLYINBYTE, Cfg->config10.bNumOnlyInByte);
     CheckDlgButton(hDlg, IDC_WORDALLOWED, Cfg->config10.bWordAllowed);
     CheckDlgButton(hDlg, IDC_SBYTEALLOWED, Cfg->config10.bSByteAllowed);
     CheckDlgButton(hDlg, IDC_ENDFILENAME, Cfg->config10.bEndNeedFilename);
     CheckDlgButton(hDlg, IDC_SHOWIMPLICITE, Cfg->config10.bShowAforImplicite);
     SetDlgItemText(hDlg, IDC_INCLUDEHEAD, Cfg->config10.szINCLUDEHead);
     SetDlgItemText(hDlg, IDC_INCLUDETAIL, Cfg->config10.szINCLUDETail);
     SetDlgItemInt(hDlg, IDC_MAXINCLUDELINES, Cfg->config10.wNbLinesPerInclude, FALSE);
     CheckRadioButton(hDlg, IDC_RADIOINCLUDE1, IDC_RADIOINCLUDE2, (Cfg->config10.bOneMainFile ? IDC_RADIOINCLUDE1 : IDC_RADIOINCLUDE2));
     CheckDlgButton(hDlg, IDC_INCLUDEALLOWED, Cfg->config10.bIncludeAllowed);
     SetDlgItemText(hDlg, IDC_DSSYNTAX, Cfg->szDS);
     CheckDlgButton(hDlg, IDC_DSALLOWED, Cfg->bDSAllowed);
}

/*
** fill Config structure with all dialog box fields.
*/
static void ConfigGetDialog(HWND hDlg, CONFIG *Cfg)
{
BOOL bTrans;

     /*
     ** ge dialog fields
     */
     GetDlgItemText(hDlg, IDC_COMMENT, Cfg->config10.szComment, MAX_CONFIG_STRING_LNG - 1);
     GetDlgItemText(hDlg, IDC_HEXNOTATION, Cfg->config10.szHex, MAX_CONFIG_STRING_LNG - 1);
     Cfg->config10.bIllegalOpcodes = (BOOL) IsDlgButtonChecked(hDlg, IDC_ILLEGALINSTRUCTION);
     Cfg->config10.bLineNumbering = (BOOL) IsDlgButtonChecked(hDlg, IDC_LINENUMBERING);
     Cfg->config10.bAlignInstructions = (BOOL) IsDlgButtonChecked(hDlg, IDC_ALIGNINSTRUCTION);
     Cfg->config10.bUseHex = (BOOL) IsDlgButtonChecked(hDlg, IDC_USEHEX);
     GetDlgItemText(hDlg, IDC_BYTESYNTAX, Cfg->config10.szBYTE, MAX_CONFIG_STRING_LNG - 1);
     GetDlgItemText(hDlg, IDC_WORDSYNTAX, Cfg->config10.szWORD, MAX_CONFIG_STRING_LNG - 1);
     GetDlgItemText(hDlg, IDC_SBYTESYNTAX, Cfg->config10.szSBYTE, MAX_CONFIG_STRING_LNG - 1);
     GetDlgItemText(hDlg, IDC_ORGSYNTAX, Cfg->config10.szORG, MAX_CONFIG_STRING_LNG - 1);
     GetDlgItemText(hDlg, IDC_EQUSYNTAX, Cfg->config10.szEQU, MAX_CONFIG_STRING_LNG - 1);
     GetDlgItemText(hDlg, IDC_ENDSYNTAX, Cfg->config10.szENDHead, MAX_CONFIG_STRING_LNG - 1);
     GetDlgItemText(hDlg, IDC_ENDTAIL, Cfg->config10.szENDTail, MAX_CONFIG_STRING_LNG - 1);
     GetDlgItemText(hDlg, IDC_LOWHEADSYNTAX, Cfg->config10.szLOWHead, MAX_CONFIG_STRING_LNG - 1);
     GetDlgItemText(hDlg, IDC_LOWTAILSYNTAX, Cfg->config10.szLOWTail, MAX_CONFIG_STRING_LNG - 1);
     GetDlgItemText(hDlg, IDC_HIGHHEADSYNTAX, Cfg->config10.szHIGHHead, MAX_CONFIG_STRING_LNG - 1);
     GetDlgItemText(hDlg, IDC_HIGHTAILSYNTAX, Cfg->config10.szHIGHTail, MAX_CONFIG_STRING_LNG - 1);
     GetDlgItemText(hDlg, IDC_BYTESEPARATOR, Cfg->config10.szByteSeparator, MAX_CONFIG_STRING_LNG - 1);
     Cfg->config10.bNumOnlyInByte = (BOOL) IsDlgButtonChecked(hDlg, IDC_NUMONLYINBYTE);
     Cfg->config10.bWordAllowed = (BOOL) IsDlgButtonChecked(hDlg, IDC_WORDALLOWED);
     Cfg->config10.bSByteAllowed = (BOOL) IsDlgButtonChecked(hDlg, IDC_SBYTEALLOWED);
     Cfg->config10.bEndNeedFilename = (BOOL) IsDlgButtonChecked(hDlg, IDC_ENDFILENAME);
     Cfg->config10.bShowAforImplicite = (BOOL) IsDlgButtonChecked(hDlg, IDC_SHOWIMPLICITE);
     GetDlgItemText(hDlg, IDC_INCLUDEHEAD, Cfg->config10.szINCLUDEHead, MAX_CONFIG_STRING_LNG - 1);
     GetDlgItemText(hDlg, IDC_INCLUDETAIL, Cfg->config10.szINCLUDETail, MAX_CONFIG_STRING_LNG - 1);
     Cfg->config10.wNbLinesPerInclude = GetDlgItemInt(hDlg, IDC_MAXINCLUDELINES, &bTrans, FALSE);
     Cfg->config10.bOneMainFile = (BOOL) IsDlgButtonChecked(hDlg, IDC_RADIOINCLUDE1);
     Cfg->config10.bIncludeAllowed = (BOOL) IsDlgButtonChecked(hDlg, IDC_INCLUDEALLOWED);
     GetDlgItemText(hDlg, IDC_DSSYNTAX, Cfg->szDS, MAX_CONFIG_STRING_LNG - 1);
     Cfg->bDSAllowed = (BOOL) IsDlgButtonChecked(hDlg, IDC_DSALLOWED);
}

/*
** load configuration from disk.
*/
static BOOL ConfigLoad(HWND hDlg, CONFIG *Cfg)
{
     if (GetFileName(hDlg, szConfigPath,
                     OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST,
                     IDS_OPEN_CONFIG,
                     "Profile files\0*.PRF\0All files\0*.*\0\0"))
          if (ConfigRead(hDlg, szConfigPath, Cfg))
               return TRUE;
     return FALSE;
}

/*
** save configuration to disk.
*/
static void ConfigSave(HWND hDlg, CONFIG *Cfg)
{
int fd;

     /*
     ** ask the user for a filename.
     */
     if (SaveFileName(hDlg, szConfigPath,
                      OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_NOREADONLYRETURN | OFN_OVERWRITEPROMPT,
                      IDS_SAVE_CONFIG,
                      "Profile files\0*.PRF\0All files\0*.*\0\0"))
          {
          if ((fd = open(szConfigPath, _O_CREAT | _O_RDWR | _O_BINARY, _S_IREAD | _S_IWRITE)) < 0)
               Error(hDlg, IDS_ERR_WRITING_FILE, "Error while writing file %s", szConfigPath);
          else {
               write(fd, CONFIG_MAGIC, strlen(CONFIG_MAGIC));
               write(fd, Cfg, sizeof(CONFIG));
               close(fd);
               }
          }
}

/*
** configuration dialog proc
*/
BOOL __export CALLBACK AsmFormatProc(HWND hDlg, UINT message, WORD wParam, LONG lParam)
{
CONFIG Cfg;

     switch (message)
          {
          case WM_INITDIALOG:
               ConfigSetDialog(hDlg, &Config);
               return TRUE;

          case WM_COMMAND:
               switch (wParam)
                    {
                    case IDOK:
                         ConfigGetDialog(hDlg, &Config);
                         DisResetLabelLines(0);
                         LabelLoad(hInst, hDlg);
                         if (wDumpSegment != NO_DUMP)
                              DumpDisassemble(hDlg);
                         EndDialog(hDlg, TRUE);
                         return TRUE;

                    case IDCANCEL:
                         EndDialog(hDlg, FALSE);
                         return TRUE;

                    case ID_LOAD_PROFILE:
                         if (ConfigLoad(hDlg, &Cfg))
                              ConfigSetDialog(hDlg, &Cfg);
                         return TRUE;

                    case ID_SAVE_PROFILE:
                         ConfigGetDialog(hDlg, &Cfg);
                         ConfigSave(hDlg, &Cfg);
                         return TRUE;
                    }
               break;

          case WM_CTLCOLOR:

               /*
               ** change background color to gray.
               */
               if (HIWORD(lParam) == CTLCOLOR_STATIC || HIWORD(lParam) == CTLCOLOR_BTN || HIWORD(lParam) == CTLCOLOR_DLG)
                    {
                    SetBkColor((HDC) wParam, RGB(192, 192, 192));
                    return (BOOL) GetStockObject(LTGRAY_BRUSH);
                    }
               return FALSE;
          }
     return FALSE;
}

/*
** display output parameters settings.
*/
long ConfigOutputFormat(HWND hWnd)
{
     DialogBox(hInst, "OUTPUTFORMATBOX", hWnd, OutputFormatProc);
     return NULL;
}

/*
** display configuration dialog
*/
long ConfigAsmFormat(HWND hWnd)
{
     DialogBox(hInst, "ASMFORMATBOX", hWnd, AsmFormatProc);
     return NULL;
}
